package com.link.base.base.wechat.service;

import com.google.gson.Gson;
import com.link.base.user.model.CoreUser;
import com.link.base.base.accnt.model.Account;
import com.link.base.base.accnt.service.AccountService;
import com.link.base.base.crowd.dao.mybatis.mapper.CrowdAcctMapper;
import com.link.base.base.crowd.model.CrowdAcct;
import com.link.base.base.crowd.service.CrowdAcctService;
import com.link.base.base.user.service.UserService;
import com.link.base.base.wechat.dao.mybatis.mapper.WxSendBatchMapper;
import com.link.base.base.wechat.model.Messageresult;
import com.link.base.base.wechat.model.WxInnerBatch;
import com.link.base.base.wechat.model.WxMedia;
import com.link.base.base.wechat.model.WxSendBatch;
import com.link.base.wechat.mpnews.model.Article;
import com.link.base.wechat.wxmessage.model.WxMessage;
import com.link.base.wechat.wxmessage.service.WxMessageService;
import com.link.base.wechat.wxplatform.dao.mybatis.mapper.WxPlatformMapper;
import com.link.base.wechat.wxplatform.model.WxPlatform;
import com.link.core.basic.dao.KeyGenerateDao;
import com.link.core.basic.dao.mapper.BasicMapper;
import com.link.core.basic.interceptor.SecurityInterceptor;
import com.link.core.basic.model.BasicModel;
import com.link.core.basic.query.Filter;
import com.link.core.basic.query.QueryParams;
import com.link.core.basic.query.Sorter;
import com.link.core.basic.service.BasicServiceException;
import com.link.core.basic.service.BasicServiceImpl;
import com.link.core.cllog.LCLogger;
import com.link.core.util.DateUtil;
import com.link.core.util.StringUtils;
import com.link.core.util.UserUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

/**
 * WxSendBatch-微信素材发送批次 
 *
 * @author 路江
 * @date 2019/05/22 10:48
 */
@Service
public class WxSendBatchServiceImpl extends BasicServiceImpl<WxSendBatch> implements WxSendBatchService {

    @Resource
    private WxSendBatchMapper wxSendBatchMapper;

    @Resource
    private WxInnerBatchService wxInnerBatchService;

    @Resource
    private WxPlatformMapper wxPlatformMapper;

    @Resource
    private WxMediaService wxMediaService;

    @Resource
    private WxMessageService wxMessageService;

    @Resource
    private AccountService accountService;

    @Resource
    private MessageresultService messageresultService;

    @Resource
    private CrowdAcctService crowdAcctService;

    @Resource
    private CrowdAcctMapper crowdAcctMapper;

    @Resource
    private KeyGenerateDao keyGenerateDao;

    @Resource
    private UserService userService;

    @Override
    public BasicMapper<WxSendBatch> getBasicMapper() {
        return wxSendBatchMapper;
    }

    @Override
    @Transactional(rollbackFor = BasicServiceException.class)
    public Map<String, Object> sendArticle(WxSendBatch wsb) throws Exception {
        Map<String, Object> result = new HashMap<>(8);
        if (wsb == null) {
            throw new BasicServiceException("请传入发送对象信息");
        }
        // 同步线程
        SendArticlesThread sendArticlesThread = new SendArticlesThread(keyGenerateDao,crowdAcctMapper,crowdAcctService,
                wxInnerBatchService,this,wsb,UserUtil.getUser(),userService);
        Thread thread = new Thread(sendArticlesThread);
        thread.start();
        return result;
    }

    @Override
    public int sendAllFollowers(WxInnerBatch wxInnerBatch) throws Exception {
        Map<String, Object> filterMap = new HashMap<>(4);
        //全部粉丝发送
        filterMap.put("is_to_all",true);
        // 素材信息
        Map<String, Object> mpnewsMap = new HashMap<>(4);
        mpnewsMap.put("media_id",wxInnerBatch.getMediaId());
        // 发送参数
        Map<String, Object> jsonMap = new HashMap<>(8);
        jsonMap.put("msgtype","mpnews");
        jsonMap.put("send_ignore_reprint",1);
        jsonMap.put("mpnews",mpnewsMap);
        jsonMap.put("filter",filterMap);
        Gson gson = new Gson();
        // 转换成特定格式字符串
        String data = gson.toJson(jsonMap);
        // 发送请求
        int n = wxMessageService.sendAllForTag(wxInnerBatch.getWxAppId(),data);
        return n;
    }

    @Override
    public int insertMsgRecord(WxSendBatch wxSendBatch, WxInnerBatch wxInnerBatch) throws Exception {
        // 全部粉丝
        String allFollowers = "AllFollowers";
        // 指定粉丝
        String selectedFollowers = "SelectedFollowers";
        if (StringUtils.equals(allFollowers,wxSendBatch.getSendTargetOption())) {
            // 查询此公众号下在我们系统的所有消费者
            Account account = new Account();
            account.setAcctType("Fans");
            account.setAcctLevel("C");
            account.setAcctChannel(wxInnerBatch.getWxAppId());
            account.setPageFlag(false);
            List<Account> list = accountService.queryByExamplePage(account);
            this.insetMsgRecord(list,wxSendBatch,wxInnerBatch);
        } else if (StringUtils.equals(selectedFollowers,wxSendBatch.getSendTargetOption())) {
            this.insetMsgRecord(null,wxSendBatch,wxInnerBatch);
        }
        return 1;
    }

    @Override
    public void insetMsgRecord(List<Account> list, WxSendBatch wxSendBatch, WxInnerBatch wxInnerBatch) throws Exception {
        // 全部粉丝
        String allFollowers = "AllFollowers";
        // 指定粉丝
        String selectedFollowers = "SelectedFollowers";
        if (StringUtils.equals(allFollowers,wxSendBatch.getSendTargetOption())) {
            for (Account account : list) {
                Messageresult messageresult = new Messageresult();
                messageresult.setStatus("Succeeded");
                messageresult.setContent(wxInnerBatch.getMediaId());
                messageresult.setContentType("mpnews");
                messageresult.setDate(DateUtil.dateToStr(new Date(),"yyyy-MM-dd HH:mm:ss"));
                messageresult.setFromUser(wxInnerBatch.getWxAppId());
                //messageresult.setOpenid(account.getWxOwnOpenId());
                messageresult.setTouser(String.valueOf(account.getId()));
                messageresult.setType("AllSend");
                messageresult.setWxId(wxInnerBatch.getWxId());
                messageresult.setResult("OK");
                messageresult.setSendId(wxSendBatch.getId());
                messageresultService.insert(messageresult);
            }
        } else if (StringUtils.equals(selectedFollowers,wxSendBatch.getSendTargetOption())) {
            for (CrowdAcct crowdAcct : wxInnerBatch.getAcctList()) {
                Messageresult messageresult = new Messageresult();
                messageresult.setStatus("Succeeded");
                messageresult.setContent(wxInnerBatch.getMediaId());
                messageresult.setContentType("mpnews");
                messageresult.setDate(DateUtil.dateToStr(new Date(),"yyyy-MM-dd HH:mm:ss"));
                messageresult.setFromUser(wxInnerBatch.getWxAppId());
                messageresult.setOpenid(crowdAcct.getKeyId());
                messageresult.setTouser(crowdAcct.getAcctId());
                messageresult.setType("AllSend");
                messageresult.setWxId(wxInnerBatch.getWxId());
                messageresult.setResult("OK");
                messageresult.setSendId(wxSendBatch.getId());
                messageresultService.insert(messageresult);
            }
        }

    }

    @Override
    public int sendselectedFollowers(WxInnerBatch wxInnerBatch) throws Exception {
        List<String> openids = new ArrayList<>();
        for (CrowdAcct acct : wxInnerBatch.getAcctList()) {
            openids.add(acct.getKeyId());
        }
        // 如果只有一个openid 增加一个假的openid使得可以群发
        if (openids.size() == 1) {
            openids.add("OPENID1");
        }
        WxMessage wxMessage = new WxMessage();
        wxMessage.setOpenIds(openids);
        wxMessage.setMsgType("mpnews");
        wxMessage.setContents(wxInnerBatch.getMediaId());
        wxMessageService.sendMsg(wxMessage,wxInnerBatch.getWxAppId());
        return 1;
    }

    @Override
    public List<WxInnerBatch> getBatchList(WxSendBatch wxSendBatch) throws Exception {
        List<WxInnerBatch> batchList = new ArrayList<>();
        Long mediaId = wxSendBatch.getMediaId();
        // 获取公众号排序
        QueryParams qps = new QueryParams();
        Sorter sorter = new Sorter("seq", Sorter.DIR_ASC);
        qps.addSorter(sorter);
        qps.setPageFlag(false);
        qps.addFilter(new Filter("wx_app_id", Filter.OP_IN, wxSendBatch.getAppIds()));
        WxPlatform wxPlatform = (WxPlatform) BasicModel
                .transformClass(WxPlatform.class, qps);
        List<WxPlatform> wxPlatforms = wxPlatformMapper.queryByExamplePage(wxPlatform);
        List<String> stringList = new ArrayList<>();
        List<Long> wxPlatIds = new ArrayList<>();
        for (WxPlatform w : wxPlatforms) {
            stringList.add(w.getWx_app_id());
            wxPlatIds.add(w.getId());
        }
        stringList.retainAll(wxSendBatch.getAppIds());
        for (String appId : stringList) {
            WxInnerBatch wxInnerBatch = new WxInnerBatch();
            wxInnerBatch.setWxId(appId);
            // 公众号信息
            wxInnerBatch.setWxAppId(appId);
            // 获取微信素材id
            WxMedia wxMedia = new WxMedia();
            wxMedia.setMediaId(mediaId);
            wxMedia.setWxId(appId);
            wxMedia.setMediaType("Article");
            wxMedia = wxMediaService.queryByMediaId(wxMedia);
            if (wxMedia == null) {
                List<Article> articles = new ArrayList<>();
                Article article = new Article();
                article.setGroupId(String.valueOf(mediaId));
                article.setWxIds(wxPlatIds);
                articles.add(article);
                wxMediaService.saveAndSendArticle(articles);
            }
            WxMedia media = new WxMedia();
            media.setMediaId(mediaId);
            media.setWxId(appId);
            media.setMediaType("Article");
            media = wxMediaService.queryByMediaId(media);
            wxInnerBatch.setMediaId(media.getWxMediaId());
            batchList.add(wxInnerBatch);
        }
        return batchList;
    }

    @Override
    public List<WxInnerBatch> queryBatchList(WxSendBatch wsb) throws Exception {
        if (wsb.getCrowdId() == null) {
            throw new BasicServiceException("人群包不能为空！");
        }
        CrowdAcct crowdAcct = new CrowdAcct();
        crowdAcct.setCrowdId(wsb.getCrowdId());
        List<CrowdAcct> crowdAcctList = crowdAcctMapper.queryAppid(crowdAcct);
        List<String> list = new ArrayList<>();
        for (CrowdAcct crowdAcct1 : crowdAcctList) {
            list.add(crowdAcct1.getAppId());
        }
        wsb.setAppIds(list);
        return this.getBatchList(wsb);
    }

    @Override
    @Transactional(rollbackFor = BasicServiceException.class)
    public void fixedTimeSendArticle() throws Exception {
        List<WxSendBatch> batchList = wxSendBatchMapper.queryByFixedTime();
        for (WxSendBatch wxSendBatch : batchList) {
            this.sendArticle(wxSendBatch);
        }
    }

    /**
     * 刷新有效人数，刷新有效消费者信息
     *
     * @author lujiang
     * @date 2019-05-27
     * @param wxSendBatch
     * @return
     */
    private WxSendBatch reflesh(WxSendBatch wxSendBatch) throws Exception {
        if (wxSendBatch == null) {
            throw new BasicServiceException("批次信息不能为空");
        }
        wxSendBatch.setWxAppId(wxSendBatch.getWxId());

        CrowdAcct crowdAcct = new CrowdAcct();
        crowdAcct.setCrowdId(wxSendBatch.getCrowdId());
        crowdAcct.setAppId(wxSendBatch.getWxAppId());
        crowdAcct.setAttr1(String.valueOf(wxSendBatch.getMediaId()));
        List<CrowdAcct> acctList = crowdAcctService.queryByCount(crowdAcct);
        wxSendBatch.setAcctList(acctList);
        // 设置有效人数
        wxSendBatch.setTargetNumber(acctList.size());
        return wxSendBatch;
    }

    /**
     * 图文推送线程
     *
     * @author lujiang
     * @date 2019-08-28
     */
    class SendArticlesThread implements Runnable {
        private KeyGenerateDao keyGenerateDao;
        private CrowdAcctMapper crowdAcctMapper;
        private CrowdAcctService crowdAcctService;
        private WxInnerBatchService wxInnerBatchService;
        private WxSendBatchService wxSendBatchService;
        private WxSendBatch wsb;
        private CoreUser user;
        private UserService userService;

        public SendArticlesThread(KeyGenerateDao keyGenerateDao, CrowdAcctMapper crowdAcctMapper,
                                  CrowdAcctService crowdAcctService, WxInnerBatchService wxInnerBatchService,
                                  WxSendBatchService wxSendBatchService, WxSendBatch wsb, CoreUser user, UserService userService) {
            this.keyGenerateDao = keyGenerateDao;
            this.crowdAcctMapper = crowdAcctMapper;
            this.crowdAcctService = crowdAcctService;
            this.wxInnerBatchService = wxInnerBatchService;
            this.wxSendBatchService = wxSendBatchService;
            this.wsb = wsb;
            this.user = user;
            this.userService = userService;
        }

        @Override
        public void run() {
            if (user == null) {
                try {
                    user = userService.queryUserByCropId(wsb.getCorpid());
                } catch (Exception e) {
                    LCLogger.withException(e.getMessage());
                }
            }
            SecurityInterceptor.tempUser.set(user);
            // 立即发送
            String imidiately = "Immediately";
            // 定时发送
            String fixedTime = "FixedTime";
            // 全部粉丝
            String allFollowers = "AllFollowers";
            // 指定粉丝
            String selectedFollowers = "SelectedFollowers";
            // 批次id
            Long id = keyGenerateDao.keyGenerate();
            // 判断是定时发送还是立即发送
            if (wsb.getId() == null) {
                wsb.setId(id);
            } else {
                wsb.setSendTimingOption("Immediately");
                wsb.setRow_status("UPDATE");
                id = wsb.getId();
            }
            Long mediaId = wsb.getMediaId();
            try {
                // 立即发送
                if (StringUtils.equals(imidiately,wsb.getSendTimingOption())) {
                    String time = DateUtil.dateToStr(new Date(),"yyyy-MM-dd HH:mm:ss");
                    List<WxInnerBatch> batchList = new ArrayList<>();
                    if (wsb.getWxIds() != null && wsb.getWxIds().size() > 0) {
                        //从入参获取批次list
                        batchList = wxSendBatchService.getBatchList(wsb);
                    } else {
                        //从人群包中查询批次list
                        batchList = wxSendBatchService.queryBatchList(wsb);
                    }
                    int number = 0;
                    try {
                        // 错误消息
                        String errMessage = "";
                        for (WxInnerBatch wxInnerBatch : batchList) {
                            // 去重查询消费者信息
                            CrowdAcct crowdAcct = new CrowdAcct();
                            crowdAcct.setAppId(wxInnerBatch.getWxAppId());
                            crowdAcct.setCrowdId(wsb.getCrowdId());
                            crowdAcct.setMediaId(mediaId);
                            // 分组查询
                            int count = crowdAcctMapper.queryOpenidCount(crowdAcct);
                            wxInnerBatch.setTargetNumber(count);
                            // 判断此批次有效人数是否大于0
                            if (wxInnerBatch.getTargetNumber() == 0) {
                                continue;
                            } else {
                                number +=  count;
                            }
                            // 根据openid 群发一次限定openid个数
                            int total = 10000;
                            // 总的openid个数
                            int num = count / total;
                            int yushu = count % total;
                            if (yushu > 0) {
                                num = num + 1;
                            }
                            try {
                                wxInnerBatch.setBatchId(id);
                                wxInnerBatch.setSyncTime(time);
                                for (int i = 0;i < num;i++) {
                                    crowdAcct.setPage(0);
                                    crowdAcct.setRows(10000);
                                    List<CrowdAcct> openids = crowdAcctService.queryOpenids(crowdAcct);
                                    wxInnerBatch.setAcctList(openids);
                                    // 全部粉丝
                                    if (StringUtils.equals(allFollowers,wsb.getSendTargetOption())) {
                                        int n = wxSendBatchService.sendAllFollowers(wxInnerBatch);
                                        // 生成消息记录
                                        int m = wxSendBatchService.insertMsgRecord(wsb,wxInnerBatch);
                                        // 指定粉丝发送
                                    } else if (StringUtils.equals(selectedFollowers,wsb.getSendTargetOption())) {
                                        int n = wxSendBatchService.sendselectedFollowers(wxInnerBatch);
                                        int m = wxSendBatchService.insertMsgRecord(wsb,wxInnerBatch);
                                    }
                                }
                                wxInnerBatch.setSyncStatus("Succeeded");
                                wxInnerBatch.setSyncComment("Succeeded");
                                wxInnerBatchService.insert(wxInnerBatch);
                            } catch (Exception e) {
                                LCLogger.error().withMessage(e.getMessage()).flush();
                                wxInnerBatch.setSyncStatus("Failed");
                                wxInnerBatch.setSyncComment("Failed");
                                wxInnerBatchService.insert(wxInnerBatch);
                                errMessage = errMessage + e.getMessage();
                            }
                        }
                        // 错误消息汇总
                        if (StringUtils.isNotBlank(errMessage)) {
                            LCLogger.error().withMessage(errMessage).flush();
                            throw new BasicServiceException(errMessage);
                        }
                        wsb.setSendTime(time);
                        wsb.setTargetNumber(number);
                        wsb.setSyncStatus("Succeeded");
                        wsb.setSyncComment("Succeeded");
                        wsb.setSyncTime(time);
                        if (StringUtils.equals("UPDATE",wsb.getRow_status())) {
                            wsb.setSendTimingOption("FixedTime");
                            wxSendBatchService.update(wsb);
                        } else {
                            wxSendBatchService.insert(wsb);
                        }
                    } catch (Exception e) {
                        wsb.setSendTime(time);
                        wsb.setSyncStatus("Failed");
                        wsb.setSyncComment("Failed");
                        wsb.setSyncTime(time);
                        if (StringUtils.equals("UPDATE",wsb.getRow_status())) {
                            wsb.setSendTimingOption("FixedTime");
                            wxSendBatchService.update(wsb);
                        } else {
                            wxSendBatchService.insert(wsb);
                        }
                    }
                } else if (StringUtils.equals(fixedTime,wsb.getSendTimingOption())) {
                    // 定时发送
                    wxSendBatchService.insert(wsb);
                }
            } catch (Exception e) {
                LCLogger.withException(e.getMessage());
            }
        }
    }
}

